﻿using System;
using System.Runtime.Remoting.Channels;
using System.Threading;
using System.Timers;
using GeneralDFS.BusinessLogical.IO;
using GeneralDFS.BusinessLogical.NodeOperate;
using GeneralDFS.BusinessLogical.RemoteObject;
using GeneralDFS.BusinessLogical.RemoteServers;
using GeneralDFS.Common.Network;
using GeneralDFS.DataEntity.Config;
using GeneralDFS.DataEntity.Enum;
using GeneralDFS.DataEntity.Nodes;
using GeneralDFS.Interface.Nodes;
using NIF.MobileActors.Core;
using NIF.MobileActors.Hosts;
using Timer = System.Timers.Timer;

namespace GeneralDFS.BusinessLogical.Nodes
{
      [Serializable]
    public partial class DataNode : IBaseNode
    {
        public DFSConfig Config;//当前节点内的全局配置文件
        public DataNodeInfoWithBlocks DataNodeInfo;
        private DataNodeConfig _dataNodeConfig;

        private NameNodeInfo _nameNodeInfo;
        public NameNodeRemoteObject NameNodeRemoteObject;
        public DataNodeRemoteServer DataNodeRemoteServer;
        //public FSVolume FsVolume;

        public DataNode()
        {
            DataNodeRemoteServer = new DataNodeRemoteServer();
        }

        public void Start()
        {
            LogUtil.LogInfo("DataNode Begin to init");
            DataNodeRemoteServer.InitServer(_dataNodeConfig, this);
            
            //启动心跳更新
            StartHeartBeat();

            //启动监听文件块
            InitListen();

            //启动Agent服务
            RemotingHost.RegisterLocal(_dataNodeConfig.Ip,_dataNodeConfig.AgentRpcPort);
            RemotingHost.Node = this;

            //获得dataNode文件块信息
            FSVolume.Init(_dataNodeConfig.DataNodeDirectory);
            //FsVolume = new FSVolume(_dataNodeConfig.DataNodeDirectory);

            //初始化索引文件
            IndexFile.Init(_dataNodeConfig.DataNodeDirectory);
            //初始化大文件
            FileData.Init(_dataNodeConfig.DataNodeDirectory);


        }

        public static DataNodeRemoteObject GetInstance(DataNodeID node)
        {
            if (node == null)
            {
                LogUtil.LogDebug("Invalid Node ({0}).", "Null Argument.");
                return null;
            }

            try
            {
                var dataNodeUri = String.Format("tcp://{0}:{1}/{2}-Server", node.Ip, node.RpcPort,
                                            node.Name);
                var retInstance = (DataNodeRemoteObject)Activator.GetObject(typeof(DataNodeRemoteObject), dataNodeUri);
                return retInstance;
            }
            catch (Exception e)
            {
                // perhaps instead we should just pass on the error?
                LogUtil.LogDebug("Unable to activate remote server {0}:{1} ({2}).", node.Ip, node.RpcPort, e.Message);
                return null;
            }
        }

        /// <summary>
        /// 判断远程Object是否有效
        /// </summary>
        /// <param name="instance"></param>
        /// <returns></returns>
        public static bool IsInstanceValid(DataNodeRemoteObject instance)
        {
            try
            {
                if (instance.Port > 0)
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            catch (Exception e)
            {
                return false;
            }
        }

        public DataNodeConfig GetNodeConfig()
        {
            return _dataNodeConfig;
        }

        private int _stop()
        {
            StopHeartBeat();
            DataNodeRemoteServer.StopServer();
            return 1;
        }

        public int Stop()
        {
            return _stop();
        }

        public int Stop(int enforce)
        {
            throw new NotImplementedException();
        }

        public void ConfigNode(object config)
        {
            _dataNodeConfig = config as DataNodeConfig;
            if (_dataNodeConfig == null) throw new ArgumentNullException("Invaild dataNodeConfig");
            DataNodeInfo = new DataNodeInfoWithBlocks(3);
                DataNodeInfo.Name = _dataNodeConfig.ServerName;
                DataNodeInfo.RpcPort = _dataNodeConfig.RpcPort;
                DataNodeInfo.Ip = _dataNodeConfig.Ip;
                DataNodeInfo.Index = _dataNodeConfig.Index;
                DataNodeInfo.TcpPort = _dataNodeConfig.TcpPort;
                //System.IO.Directory.CreateDirectory(_dataNodeConfig.DataNodeDirectory);
        }

        /// <summary>
        /// 配置Local模式下的当前节点
        /// </summary>
        /// <param name="settings"></param>
        public void ConfigLocal(object settings)
        {
            var currentSettings = settings as CurrentSettings;
            if (currentSettings != null)
                Config.CurrentSettings = new CurrentSettings
                {
                    Index = currentSettings.Index,
                    NodeType = currentSettings.NodeType
                };
        }
    }
}